''' <summary>
''' Class for all classes to read BMD data
''' </summary>
Public Class clsDataBMD
    Inherits clsData

    'local variable(s) to hold property value(s)
    Private _BMD As clsBMD
    Private _TimeNum As Integer
    Private _SegmentNum As Integer 'keeps track of current segment number; sequential reads loop through all times, then all stations,

    ''' <summary>
    ''' Flag to set whether entire contents of BMD is loaded into RAM or kept on disk
    ''' </summary>
    Public Property InRam() As Boolean
        Get
            Return _BMD.InRam
        End Get
        Set(ByVal value As Boolean)
            _BMD.InRam = value
        End Set
    End Property

    Public Overrides Sub Initialize(ByVal _Filename As String)
        MyBase.Initialize(_Filename)
        mDataType = enumDataType.BMD
        _BMD = New clsBMD(_Filename, False, , False)
        With _BMD
            For Each s As String In .SegmentNames
                If Not mStationIDs.Contains(s) Then mStationIDs.Add(s)
            Next

            'treat bmd file as a tabular data file, where the station ID (segment) and date-time are in columns 0 and 1, and each variable is in subsequent columns
            mFieldNames.Clear()
            mFieldNames.Add("Station_ID")
            mFieldNames.Add("Date_Time")
            ReDim mMinValue(.NumVars + 2 - 1)
            ReDim mMaxValue(.NumVars + 2 - 1)
            For v As Integer = 0 To .NumVars - 1
                Dim PCode As String = .VarName(v).Replace(Chr(0), "").Trim & IIf(.VarUnits(v).Trim = "", "", " (" & .VarUnits(v).Replace(Chr(0), "").Trim & ")")
                If Not mFieldNames.Contains(PCode) Then
                    mFieldNames.Add(PCode)
                    mPCodes.Add(PCode)
                    mMinValue(mFieldNames.Count - 1) = .VarMin(v)
                    mMaxValue(mFieldNames.Count - 1) = .VarMax(v)
                End If
            Next
            mMinDate = _BMD.Time(0)
            mMaxDate = _BMD.Time(_BMD.NumTimes - 1)
            _SegmentNum = 0
        End With
    End Sub

    Public Overrides Property ActiveStationID() As String
        Get
            Return MyBase.ActiveStationID
        End Get
        Set(ByVal value As String)
            MyBase.ActiveStationID = value
            _SegmentNum = StationIDs.IndexOf(value)
        End Set
    End Property

    ''' <summary>
    ''' Read next line from file into memory, storing into mItems array
    ''' Also save mLastLineRead for error reporting
    ''' </summary>
    ''' <returns>True if successful, false if eof reached and no more data</returns>
    Public Overrides Function Read() As Boolean
        Try
            If Not MyBase.Read() Then Return False
            With _BMD
                If _TimeNum > .NumTimes - 1 Then 'go to next segment
                    If mActiveStationIDSet Then
                        Return False 'only read one stationid
                    Else
                        _SegmentNum += 1
                        _TimeNum = 0
                        If _SegmentNum > .NumSegments - 1 Then Return False
                    End If
                End If
                mItems.Clear()
                mItems.Add(.SegmentNames(_SegmentNum))
                mItems.Add(.Time(_TimeNum).ToString(MyDateTimeFormat))
                Dim ConcAtTime() As Single = .Conc(_SegmentNum, _TimeNum)

                For i As Integer = 0 To .NumVars - 1
                    'mItems.Add(.Conc(i, _SegmentNum, _TimeNum))
                    mItems.Add(ConcAtTime(i))
                Next
                _TimeNum += 1
                Return True
            End With
        Catch ex As Exception
            ErrorMsg(, ex)
            Return False
        End Try
    End Function

    Public Overrides Sub Rewind()
        MyBase.Rewind()
        _TimeNum = 0
        _SegmentNum = 0
    End Sub

    ''' <summary>
    ''' Determine percent of file that has been read
    ''' </summary>
    ''' <returns>Percent of file read</returns>
    Public Overrides Function PercentComplete() As Double
        Return mRecordNum * 100.0 / (_BMD.NumTimes * _BMD.NumSegments)
    End Function

    ''' <summary>
    ''' Determine min/max values for each pcodes regardless of station id; generic version uses brute force by looping over all entries
    ''' </summary>
    ''' <remarks></remarks>
    Protected Overrides Sub GetMinMaxDates()
        mMinDate = _BMD.Times(0)
        mMaxDate = _BMD.Times(_BMD.NumTimes - 1)
    End Sub

    ''' <summary>
    ''' Get data table containing time series data for all stations and pcodes
    ''' Table will contain station_id, date-time, and all variable fields
    ''' </summary>
    Public Overloads Function GetDataTable() As System.Data.DataTable
        Dim dt As DataTable = MyBase.SetupDataTable(enumDataTableColumns.All)
        With _BMD
            For s As Integer = 0 To .NumSegments - 1
                For v As Integer = 0 To .NumVars - 1
                    For t As Integer = 0 To .NumTimes - 1
                        Dim r As DataRow = dt.NewRow
                        r(0) = .SegmentName(s)
                        r(1) = .Time(t).ToString(MyDateTimeFormat)
                        For j As Integer = 0 To .NumVars - 1
                            r.Item(j + 2) = .Conc(v, s, t)
                        Next
                        dt.Rows.Add(r)
                    Next
                Next
                RaiseProgress(s, .NumSegments - 1, "Loading data...")
            Next
        End With
        Return dt
    End Function

    ''' <summary>
    ''' Get data table containing time series data for a specified station id and pcode
    ''' Table will contain date-time field and result field
    ''' </summary>
    Public Overloads Function GetDataTable(ByVal StationID As String, ByVal PCode As String) As DataTable
        Dim staNum As Integer = -1
        If mStationIDs.Contains(StationID) Then
            staNum = mStationIDs.IndexOf(StationID)
        Else
            Throw New ApplicationException("BMD file does not contain the station: " & StationID)
            Return Nothing
        End If
        Dim itemNum As Integer = -1
        If ContainsFieldName(PCode) Then
            itemNum = mPCodes.IndexOf(PCode)
        Else
            Throw New ApplicationException("BMD file does not contain the column: " & PCode)
            Return Nothing
        End If
        Dim dt As DataTable = MyBase.GetDataTable(StationID, PCode)
        With _BMD
            For t As Integer = 0 To .NumTimes - 1
                Dim result As Single = .Conc(itemNum, staNum, t)
                Debug.Assert(Not Single.IsNaN(result))
                dt.Rows.Add(.Time(t), result)
                RaiseProgress(t, .NumTimes - 1, "Loading data...")
            Next
        End With
        Return dt
    End Function

    ''' <summary>
    ''' Get data table containing time series data for a all stations and pcode
    ''' Table will contain station field, date-time field and result field
    ''' </summary>
    Public Overloads Function GetDataTable(ByVal StationIDs() As String, ByVal PCode As String) As DataTable
        Dim StationNums(StationIDs.Length - 1) As Integer
        For i As Integer = 0 To StationIDs.Length - 1
            Dim staNum As Integer = -1
            If mStationIDs.Contains(StationIDs(i)) Then
                StationNums(i) = mStationIDs.IndexOf(StationIDs(i))
            Else
                Throw New ApplicationException("BMD file does not contain the station: " & StationIDs(i))
                Return Nothing
            End If
        Next
        Dim itemNum As Integer = -1
        If ContainsFieldName(PCode) Then
            itemNum = mPCodes.IndexOf(PCode)
        Else
            Throw New ApplicationException("BMD file does not contain the column: " & PCode)
            Return Nothing
        End If

        Dim dt As DataTable = MyBase.SetupDataTable(enumDataTableColumns.Station_Result)
        With _BMD
            For t As Integer = 0 To .NumTimes - 1
                Dim Concs(,) As Single = .Conc(t)
                Dim t1 As Date = .Time(t)
                For i As Integer = 0 To StationNums.Length - 1
                    Dim result As Single = Concs(StationNums(i), itemNum)
                    dt.Rows.Add(StationIDs(i), t1, result)
                Next
                RaiseProgress(t, .NumTimes - 1, "Loading data...")
                Erase Concs
            Next
        End With
        Erase StationNums
        Return dt
    End Function

    ''' <summary>
    ''' Get data table containing all data in given time range for all station ids and pcode
    ''' Table will contain station and result field
    ''' </summary>
    Public Overloads Function GetDataTable(ByVal StationIDs() As String, ByVal PCode As String, MinDate As Date, MaxDate As Date) As DataTable
        Dim StationNums(StationIDs.Length - 1) As Integer
        For i As Integer = 0 To StationIDs.Length - 1
            Dim staNum As Integer = -1
            If mStationIDs.Contains(StationIDs(i)) Then
                StationNums(i) = mStationIDs.IndexOf(StationIDs(i))
            Else
                Throw New ApplicationException("BMD file does not contain the station: " & StationIDs(i))
                Return Nothing
            End If
        Next
        Dim itemNum As Integer = -1
        If ContainsFieldName(PCode) Then
            itemNum = mPCodes.IndexOf(PCode)
        Else
            Throw New ApplicationException("BMD file does not contain the column: " & PCode)
            Return Nothing
        End If

        Dim dt As DataTable = MyBase.SetupDataTable(enumDataTableColumns.Station_Date_Result)
        With _BMD
            Dim tmin As Integer = .TimeIndex(MinDate)
            Dim tmax As Integer = .TimeIndex(MaxDate)
            For t As Integer = tmin To tmax
                Dim Concs(,) As Single = .Conc(t, t = tmin)
                Dim t1 As Date = .Time(t)
                For i As Integer = 0 To StationNums.Length - 1
                    Dim result As Single = Concs(StationNums(i), itemNum)
                    dt.Rows.Add(StationIDs(i), result)
                Next
                'RaiseProgress(t - tmin, tmax - tmin, "Loading data...")
                Erase Concs
            Next
        End With
        Erase StationNums
        Return dt
    End Function

    Public Overrides Sub Close()
        MyBase.Close()
        _BMD.Close()
    End Sub
End Class

